<template>
  <div class="excel-compare-container">
    <!-- 全屏动画遮罩层，现在用于对比和下载过程 -->
    <transition name="fade">
      <div class="fullscreen-loader" v-if="showCompareAnimation || showDownloadAnimation">
        <div class="compare-animation">
          <div class="compare-spinner"></div>
          <h2 class="compare-text">{{ animationTitle }}</h2>
          <div class="compare-stage">{{ animationStage }}</div>
          <div class="progress-container">
            <div class="progress-bar" :style="{ width: animationProgress + '%' }"></div>
          </div>
          <div class="progress-text">{{ animationProgress }}% 完成</div>
        </div>
      </div>
    </transition>

    <div class="excel-compare">
      <div class="card">
        <div class="card-header">
          <h2>大Excel对比工具</h2>
        </div>

        <div class="upload-section">
          <div class="file-uploads">
            <div class="file-upload-container">
              <h3>Excel文件 1</h3>
              <div
                class="file-upload"
                @drop.prevent="handleDrop($event, 1)"
                @dragover.prevent="handleDragOver"
                @dragleave.prevent="handleDragLeave"
              >
                <input
                  type="file"
                  id="file1"
                  accept=".xlsx,.xls"
                  @change="(e) => handleFileChange(e, 1)"
                  class="file-input"
                />
                <label for="file1" class="upload-button">选择Excel文件</label>
                <div class="drag-tip">或将文件拖到此处</div>
                <div class="file-name" v-if="file1">已选择: {{ file1.name }}</div>
                <div class="file-info" v-if="excel1Data.length > 0">
                  总行数: {{ excel1Data.length - 1 }} 行
                </div>
                <div class="loading-spinner" v-if="isLoadingExcel1">
                  <div class="spinner"></div>
                  <div class="loading-text">正在加载Excel数据...</div>
                </div>
              </div>
            </div>

            <div class="file-upload-container">
              <h3>Excel文件 2</h3>
              <div
                class="file-upload"
                @drop.prevent="handleDrop($event, 2)"
                @dragover.prevent="handleDragOver"
                @dragleave.prevent="handleDragLeave"
              >
                <input
                  type="file"
                  id="file2"
                  accept=".xlsx,.xls"
                  @change="(e) => handleFileChange(e, 2)"
                  class="file-input"
                />
                <label for="file2" class="upload-button">选择Excel文件</label>
                <div class="drag-tip">或将文件拖到此处</div>
                <div class="file-name" v-if="file2">已选择: {{ file2.name }}</div>
                <div class="file-info" v-if="excel2Data.length > 0">
                  总行数: {{ excel2Data.length - 1 }} 行
                </div>
                <div class="loading-spinner" v-if="isLoadingExcel2">
                  <div class="spinner"></div>
                  <div class="loading-text">正在加载Excel数据...</div>
                </div>
              </div>
            </div>
          </div>
        </div>

        <!-- Excel1 数据预览区域 -->
        <div class="preview-section" v-if="excel1Preview.length > 0">
          <h3>Excel 1 数据预览（前5行）</h3>
          <div class="table-wrapper">
            <table class="preview-table">
              <thead>
                <tr>
                  <th v-for="(header, index) in excel1Headers" :key="index">
                    {{ header }}
                  </th>
                </tr>
              </thead>
              <tbody>
                <tr v-for="(row, rowIndex) in excel1Preview.slice(1, 6)" :key="rowIndex">
                  <td v-for="(cell, cellIndex) in row" :key="cellIndex">
                    {{ cell }}
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
        </div>

        <!-- 排序配置 -->
        <div class="sort-section" v-if="excel1Headers.length > 0">
          <h3>
            排序配置
            <span class="sort-info" v-if="compareMode === 'key'">
              (这些字段将作为对比的唯一标识)
            </span>
          </h3>
          <div class="sort-header">
            <div class="sort-header-left">
              <span class="header-text">列</span>
            </div>
            <div class="sort-header-center">
              <span class="header-text">排序依据</span>
            </div>
            <div class="sort-header-right">
              <span class="header-text">次序</span>
            </div>
          </div>

          <div class="sort-configs">
            <div class="sort-item" v-for="(config, index) in sortConfigs" :key="index">
              <div class="sort-item-left">
                <select
                  v-model="config.field"
                  class="select-input"
                  @change="
                    updateSortConfig(index, 'field', ($event.target as HTMLSelectElement).value)
                  "
                >
                  <option v-for="header in excel1Headers" :key="header" :value="header">
                    {{ header }}
                  </option>
                </select>
              </div>
              <div class="sort-item-center">
                <select
                  v-model="config.type"
                  class="select-input"
                  @change="
                    updateSortConfig(index, 'type', ($event.target as HTMLSelectElement).value)
                  "
                >
                  <option value="string">文本</option>
                  <option value="number">数值</option>
                </select>
              </div>
              <div class="sort-item-right">
                <select
                  v-model="config.order"
                  class="select-input"
                  @change="
                    updateSortConfig(index, 'order', ($event.target as HTMLSelectElement).value)
                  "
                >
                  <option value="asc">升序</option>
                  <option value="desc">降序</option>
                </select>
              </div>
              <div class="sort-item-actions">
                <button class="icon-btn" @click="addSortConfig" title="添加条件">
                  <span class="icon">+</span>
                </button>
                <button
                  class="icon-btn"
                  @click="removeSortConfig(index)"
                  title="删除条件"
                  :disabled="sortConfigs.length <= 1"
                >
                  <span class="icon">-</span>
                </button>
                <button class="icon-btn" @click="copySortConfig(index)" title="复制条件">
                  <span class="icon">&#x2398;</span>
                </button>
              </div>
            </div>
          </div>
        </div>

        <!-- 添加开始对比按钮到字段配置表格上方 -->
        <div class="action-section" v-if="file1 && file2">
          <button
            class="compare-btn"
            @click="compareExcel"
            :disabled="!file1 || !file2 || isComparing || isLoadingExcel1 || isLoadingExcel2"
          >
            {{ isComparing ? '对比中...' : '开始对比' }}
          </button>
        </div>

        <!-- 移动对比方式配置到此处 -->
        <div class="config-section" v-if="excel1Headers.length > 0">
          <div class="config-item">
            <label class="config-label">对比方式：</label>
            <select v-model="compareMode" class="select-input">
              <option value="key">按排序字段对比</option>
              <option value="position">按位置对比</option>
            </select>
          </div>

          <!-- 隐藏原关键列选择器 -->
          <!--
          <div class="config-item" v-if="compareMode === 'key'">
            <label class="config-label">关键列：</label>
            <select v-model="keyColumn" class="select-input">
              <option v-for="header in excel1Headers" :key="header" :value="header">
                {{ header }}
              </option>
            </select>
          </div>
          -->

          <div class="config-item" v-if="compareMode === 'key' && sortConfigs.length === 0">
            <span class="warning-text">请至少添加一个排序字段作为对比依据</span>
          </div>

          <div class="config-item">
            <label class="checkbox-wrapper">
              <input type="checkbox" v-model="ignoreCase" />
              <span>忽略大小写</span>
            </label>
          </div>

          <div class="config-item">
            <label class="checkbox-wrapper">
              <input type="checkbox" v-model="ignoreSpaces" />
              <span>忽略空格</span>
            </label>
          </div>
        </div>

        <!-- 字段配置表格 -->
        <div class="columns-config-section" v-if="columnConfigs.length > 0">
          <h3>字段配置表格</h3>
          <div class="table-wrapper">
            <table class="config-table">
              <thead>
                <tr>
                  <th>字段名称</th>
                  <th class="checkbox-cell">
                    <div class="th-content">
                      <span class="th-label">是否对比</span>
                      <div class="select-all-controls">
                        <button class="mini-btn select-all" @click="selectAllColumns">全选</button>
                        <button class="mini-btn deselect-all" @click="deselectAllColumns">
                          全不选
                        </button>
                      </div>
                    </div>
                  </th>
                  <th>是否为数字</th>
                  <th>忽略小数位</th>
                  <th>对比结果</th>
                  <th>示例</th>
                </tr>
              </thead>
              <tbody>
                <tr v-for="(config, index) in columnConfigs" :key="index">
                  <td>{{ config.name }}</td>
                  <td class="checkbox-cell">
                    <label class="checkbox-wrapper">
                      <input
                        type="checkbox"
                        :checked="config.shouldCompare"
                        @change="
                          (e) =>
                            updateColumnConfig(
                              index,
                              'shouldCompare',
                              (e.target as HTMLInputElement).checked,
                            )
                        "
                      />
                    </label>
                  </td>
                  <td>
                    <label class="checkbox-wrapper">
                      <input
                        type="checkbox"
                        :checked="config.isNumeric"
                        @change="
                          (e) =>
                            updateColumnConfig(
                              index,
                              'isNumeric',
                              (e.target as HTMLInputElement).checked,
                            )
                        "
                      />
                    </label>
                  </td>
                  <td>
                    <input
                      type="number"
                      class="digit-input"
                      min="0"
                      max="10"
                      :value="config.ignoreDigits"
                      @change="
                        (e) =>
                          updateColumnConfig(
                            index,
                            'ignoreDigits',
                            parseInt((e.target as HTMLInputElement).value) || 0,
                          )
                      "
                      :disabled="!config.isNumeric"
                    />
                  </td>
                  <td
                    :class="{
                      'status-identical': config.comparisonResult === 'identical',
                      'status-different': config.comparisonResult === 'different',
                      'status-not-exist': config.comparisonResult === 'not-exist',
                    }"
                  >
                    {{ getColumnComparisonStatusText(config.comparisonResult) }}
                  </td>
                  <td>
                    <div v-if="config.examples.length > 0" class="examples-wrapper">
                      <div
                        class="example-item"
                        v-for="(example, exIndex) in config.examples"
                        :key="exIndex"
                      >
                        <div class="example-row">
                          <span class="row-label">行号:</span>
                          <span class="row-value"
                            >Excel1:
                            <span class="row-number">{{
                              example.rowNum1 !== undefined ? example.rowNum1 + 1 : '未知'
                            }}</span></span
                          >
                          <span class="row-value"
                            >Excel2:
                            <span class="row-number">{{
                              example.rowNum2 !== undefined && example.rowNum2 !== -1
                                ? example.rowNum2 + 1
                                : '未知'
                            }}</span></span
                          >
                        </div>
                        <div class="example-content">
                          Excel1: <span class="value">{{ example.excel1 }}</span> Excel2:
                          <span class="value">{{ example.excel2 }}</span>
                        </div>
                        <div class="example-unique-key">
                          <span class="key-label">唯一索引号:</span>
                          <span class="key-value">{{ example.uniqueKey }}</span>
                        </div>
                      </div>
                    </div>
                    <span v-else>-</span>
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
        </div>

        <!-- 对比结果 -->
        <div class="result-section" v-if="comparisonResult">
          <h3>对比结果</h3>

          <div class="result-summary">
            <div class="summary-item">
              <span class="label">总行数：</span>
              <span class="value">{{ comparisonResult.totalRows }}</span>
            </div>
            <div class="summary-item">
              <span class="label">相同行数：</span>
              <span class="value">{{ comparisonResult.matchedRows }}</span>
            </div>
            <div class="summary-item">
              <span class="label">不同行数：</span>
              <span class="value">{{ comparisonResult.differentRows }}</span>
            </div>
            <div class="summary-item">
              <span class="label">文件1独有：</span>
              <span class="value">{{ comparisonResult.onlyInFile1 }}</span>
            </div>
            <div class="summary-item">
              <span class="label">文件2独有：</span>
              <span class="value">{{ comparisonResult.onlyInFile2 }}</span>
            </div>
          </div>

          <div class="result-actions">
            <button class="download-btn" @click="downloadResultsAsCsv">下载对比结果(CSV)</button>
          </div>

          <!-- 差异预览 -->
          <div class="diff-preview" v-if="comparisonResult.differences.length > 0">
            <h4>差异预览（显示前10条）</h4>
            <div class="table-wrapper">
              <table class="diff-table">
                <thead>
                  <tr>
                    <th>行号</th>
                    <th>类型</th>
                    <th>文件1内容</th>
                    <th>文件2内容</th>
                  </tr>
                </thead>
                <tbody>
                  <tr
                    v-for="(diff, index) in comparisonResult.differences.slice(0, 10)"
                    :key="index"
                    :class="diff.type"
                  >
                    <td>{{ diff.row }}</td>
                    <td>{{ getDiffTypeText(diff.type) }}</td>
                    <td>{{ diff.content1 || '-' }}</td>
                    <td>{{ diff.content2 || '-' }}</td>
                  </tr>
                </tbody>
              </table>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 自定义加载提示内容 -->
    <div v-if="false" class="el-loading-custom-content">
      <h3 class="loading-title">{{ animationTitle }}</h3>
      <div class="loading-stage">{{ animationStage }}</div>
      <div class="progress-container">
        <el-progress
          :percentage="animationProgress"
          :stroke-width="10"
          :show-text="false"
        ></el-progress>
      </div>
      <div class="progress-text">{{ animationProgress }}% 完成</div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onUnmounted, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import * as XLSX from 'xlsx'
import { indexedDBUtil } from '@/utils/indexedDB'
import { ExcelReader } from '@/utils/excelReader'

// 文件和配置
const file1 = ref<File | null>(null)
const file2 = ref<File | null>(null)
const compareMode = ref('key')
const keyColumn = ref('')
const ignoreCase = ref(true)
const ignoreSpaces = ref(true)
const isComparing = ref(false)
// 添加全屏对比动画控制变量
const showCompareAnimation = ref(false)
// 添加对比进度状态
const compareProgress = ref(0)
// 添加当前对比阶段描述
const compareStage = ref('准备中...')

// 添加排序配置
const sortConfigs = ref<
  Array<{
    field: string
    type: 'number' | 'string'
    order: 'asc' | 'desc'
  }>
>([])

// 添加Excel加载状态
const isLoadingExcel1 = ref(false)
const isLoadingExcel2 = ref(false)

// 添加Excel1预览数据相关状态
const excel1Data = ref<any[]>([])
const excel1Headers = ref<string[]>([])
const excel1Preview = ref<any[]>([])

// 添加Excel2数据相关状态
const excel2Headers = ref<string[]>([])
const excel2Data = ref<any[]>([])

// 添加字段配置相关状态
const columnConfigs = ref<
  Array<{
    name: string
    shouldCompare: boolean
    isNumeric: boolean
    ignoreDigits: number
    comparisonResult: string
    examples: Array<{
      excel1: any
      excel2: any
      rowNum1?: number
      rowNum2?: number
      uniqueKey: string
    }>
  }>
>([])

interface ComparisonDifference {
  row: number
  type: 'different' | 'only-in-file1' | 'only-in-file2'
  content1: string | null
  content2: string | null
}

interface ComparisonResult {
  totalRows: number
  matchedRows: number
  differentRows: number
  onlyInFile1: number
  onlyInFile2: number
  differences: ComparisonDifference[]
}

// 对比结果
const comparisonResult = ref<ComparisonResult | null>(null)

// 添加全屏动画控制变量
const showDownloadAnimation = ref(false)
// 添加下载进度状态
const downloadProgress = ref(0)
// 添加下载当前阶段描述
const downloadStage = ref('准备中...')

// 计算属性用于动画内容
const animationTitle = computed(() => {
  return showCompareAnimation.value ? '正在对比Excel数据' : '正在导出差异结果'
})

const animationStage = computed(() => {
  return showCompareAnimation.value ? compareStage.value : downloadStage.value
})

const animationProgress = computed(() => {
  return showCompareAnimation.value ? compareProgress.value : downloadProgress.value
})

// 在组件加载时清空IndexedDB
onMounted(async () => {
  try {
    await indexedDBUtil.clearAllData()
  } catch (error) {
    console.error('清空数据库失败:', error)
  }
})

// 处理文件选择
const handleFileChange = async (event: Event, fileNum: number) => {
  const input = event.target as HTMLInputElement
  const file = input.files?.[0]
  if (!file) return

  if (
    !file.name.endsWith('.xlsx') &&
    !file.name.endsWith('.xls') &&
    !file.type.includes('excel') &&
    !file.type.includes('spreadsheet')
  ) {
    ElMessage.error('请选择Excel文件(.xlsx或.xls)')
    input.value = ''
    return
  }

  try {
    if (fileNum === 1) {
      file1.value = file
      isLoadingExcel1.value = true

      // 只读取预览数据
      const { headers, previewData } = await ExcelReader.readExcelPreview(file)

      // 更新UI状态
      excel1Headers.value = headers
      excel1Data.value = [headers, ...previewData]
      excel1Preview.value = excel1Data.value

      // 初始化列配置
      columnConfigs.value = headers.map((header) => ({
        name: header,
        shouldCompare: true,
        isNumeric: false,
        ignoreDigits: 0,
        comparisonResult: '',
        examples: [],
      }))

      // 如果没有排序配置，添加一个默认的排序配置
      if (sortConfigs.value.length === 0 && headers.length > 0) {
        sortConfigs.value.push({
          field: headers[0],
          type: 'string',
          order: 'asc',
        })
      }

      // 默认选择第一列作为关键列
      if (!keyColumn.value && headers.length > 0) {
        keyColumn.value = headers[0]
      }
    } else {
      file2.value = file
      excel2Headers.value = [] // 清空Excel2的表头，因为我们现在只存储文件
    }

    ElMessage.success('Excel文件加载完成')
  } catch (error) {
    console.error('Excel文件处理失败:', error)
    ElMessage.error('Excel文件处理失败，请重试')
  } finally {
    if (fileNum === 1) {
      isLoadingExcel1.value = false
    } else {
      isLoadingExcel2.value = false
    }
  }
}

// 生成行的唯一ID
const generateRowId = (rowData: any[], sortFieldIndices: number[]): string => {
  return sortFieldIndices.map((index) => normalizeValue(rowData[index])).join('_')
}

// 处理拖拽
const handleDragOver = (event: DragEvent) => {
  event.target && (event.target as HTMLElement).closest('.file-upload')?.classList.add('dragover')
}

const handleDragLeave = (event: DragEvent) => {
  event.target &&
    (event.target as HTMLElement).closest('.file-upload')?.classList.remove('dragover')
}

const handleDrop = async (event: DragEvent, fileNum: number) => {
  event.target &&
    (event.target as HTMLElement).closest('.file-upload')?.classList.remove('dragover')
  const file = event.dataTransfer?.files[0]
  if (!file) return

  if (
    !file.name.endsWith('.xlsx') &&
    !file.name.endsWith('.xls') &&
    !file.type.includes('excel') &&
    !file.type.includes('spreadsheet')
  ) {
    ElMessage.error('请选择Excel文件(.xlsx或.xls)')
    return
  }

  // 创建一个新的 FileList 对象
  const dataTransfer = new DataTransfer()
  dataTransfer.items.add(file)

  // 更新 input 的文件
  const fileInput = document.getElementById(`file${fileNum}`) as HTMLInputElement
  if (fileInput) {
    fileInput.files = dataTransfer.files
    // 直接调用handleFileChange处理文件
    await handleFileChange({ target: fileInput } as unknown as Event, fileNum)
  }
}

// 添加排序配置
const addSortConfig = () => {
  if (excel1Headers.value.length === 0) return

  sortConfigs.value.push({
    field: excel1Headers.value[0],
    type: 'string',
    order: 'asc',
  })
}

// 删除排序配置
const removeSortConfig = (index: number) => {
  sortConfigs.value.splice(index, 1)
}

// 复制排序配置
const copySortConfig = (index: number) => {
  const config = { ...sortConfigs.value[index] }
  sortConfigs.value.splice(index + 1, 0, config)
}

// 更新排序配置
const updateSortConfig = (index: number, field: string, value: any) => {
  if (sortConfigs.value[index]) {
    if (field === 'field') {
      sortConfigs.value[index].field = value
    } else if (field === 'type') {
      sortConfigs.value[index].type = value
    } else if (field === 'order') {
      sortConfigs.value[index].order = value
    }
  }
}

// 更新列配置
const updateColumnConfig = (index: number, field: string, value: any) => {
  if (columnConfigs.value[index]) {
    if (field === 'shouldCompare') {
      columnConfigs.value[index].shouldCompare = value
    } else if (field === 'isNumeric') {
      columnConfigs.value[index].isNumeric = value
    } else if (field === 'ignoreDigits') {
      columnConfigs.value[index].ignoreDigits = value
    }
  }
}

// 获取列对比结果状态文本
const getColumnComparisonStatusText = (status: string): string => {
  switch (status) {
    case 'identical':
      return '完全一致'
    case 'not-exist':
      return 'Excel2中不存在该列'
    case 'different':
      return '存在不一致'
    default:
      return '未对比'
  }
}

// 对比Excel文件
const compareExcel = async () => {
  console.log('开始比较excel文件')
  if (!file1.value || !file2.value) {
    ElMessage.warning('请选择两个Excel文件进行对比')
    return
  }

  isComparing.value = true
  compareProgress.value = 0
  compareStage.value = '准备中...'
  showCompareAnimation.value = true

  try {
    // 清空之前的数据
    await indexedDBUtil.clearAllData()

    // 重置列配置的比较结果
    columnConfigs.value.forEach((config) => {
      config.comparisonResult = ''
      config.examples = []
    })

    // 1. 首先处理Excel2的数据
    compareStage.value = '正在加载Excel2数据...'
    const { headers: headers2 } = await ExcelReader.readExcelPreview(file2.value)
    excel2Headers.value = headers2

    // 检查Excel2中的列是否存在，并标记不存在的列
    columnConfigs.value.forEach((config) => {
      if (!headers2.includes(config.name)) {
        config.comparisonResult = 'not-exist'
        config.examples = []
      }
    })

    // 获取排序字段的索引
    const sortFieldIndices: number[] = []
    for (const config of sortConfigs.value) {
      const index = headers2.findIndex((h: string) => h === config.field)
      if (index !== -1) {
        sortFieldIndices.push(index)
      }
    }

    // 流式读取Excel2并写入IndexedDB
    compareStage.value = '正在处理Excel2数据...'
    compareProgress.value = 10

    for await (const { rowData: row2, rowIndex: rowIndex2 } of ExcelReader.readExcelStream(
      file2.value,
      (progress) => {
        compareProgress.value = 10 + progress * 0.3 // 进度从10%到40%
        compareStage.value = `正在处理Excel2数据... ${Math.floor(progress * 100)}%`
      },
    )) {
      if (rowIndex2 === 0) continue // 跳过表头行

      // 生成行的唯一ID
      const rowId = generateRowId(row2, sortFieldIndices)

      // 保存到IndexedDB
      await indexedDBUtil.saveExcel2Row({
        id: rowId,
        rowData: row2,
        rowIndex: rowIndex2,
      })
    }

    // 创建列差异统计对象
    const columnStats = new Map<
      number,
      {
        different: number
        examples: Array<{
          excel1: any
          excel2: any
          rowNum1: number
          rowNum2: number
          uniqueKey: string
        }>
      }
    >()

    // 初始化列统计
    columnConfigs.value.forEach((config, index) => {
      if (config.comparisonResult !== 'not-exist') {
        columnStats.set(index, {
          different: 0,
          examples: [],
        })
      }
    })

    // 2. 流式读取Excel1并进行比较
    compareStage.value = '正在比较数据...'
    compareProgress.value = 40

    for await (const { rowData: row1, rowIndex: rowIndex1 } of ExcelReader.readExcelStream(
      file1.value,
      (progress, stage) => {
        compareProgress.value = 40 + progress * 0.6
        compareStage.value = stage
      },
    )) {
      if (rowIndex1 === 0) continue // 跳过表头行

      const rowId = generateRowId(row1, sortFieldIndices)
      const excel2Record = await indexedDBUtil.findExcel2RowById(rowId)
      console.log('excel2Record', excel2Record)
      if (!excel2Record) {
        // 当数据在excel2中不存在时
        await indexedDBUtil.saveCompareResult({
          type: 'only-in-file1',
          excel1Data: row1,
          excel2Data: [],
          rowNum1: rowIndex1,
          rowNum2: -1,
        })

        // 更新所有需要对比的列的统计信息
        for (let i = 0; i < row1.length; i++) {
          const columnConfig = columnConfigs.value[i]
          if (
            columnConfig &&
            columnConfig.shouldCompare &&
            columnConfig.comparisonResult !== 'not-exist'
          ) {
            const colStat = columnStats.get(i)
            if (colStat) {
              colStat.different++

              // 只保存前3个示例
              if (colStat.examples.length < 3) {
                colStat.examples.push({
                  excel1: row1[i],
                  excel2: 'excel2中不存在',
                  rowNum1: rowIndex1,
                  rowNum2: -1,
                  uniqueKey: generateRowId(row1, sortFieldIndices),
                })
              }
            }
          }
        }
      } else {
        const row2 = excel2Record.rowData
        let isDifferent = false
        const differences = []

        // 比较每一列
        for (let i = 0; i < row1.length; i++) {
          const columnConfig = columnConfigs.value[i]
          if (
            columnConfig &&
            columnConfig.shouldCompare &&
            columnConfig.comparisonResult !== 'not-exist'
          ) {
            let val1 = row1[i]
            let val2 = row2[i]

            // 处理数字类型比较
            if (columnConfig.isNumeric && columnConfig.ignoreDigits > 0) {
              if (typeof val1 === 'number' && typeof val2 === 'number') {
                const factor = Math.pow(10, columnConfig.ignoreDigits)
                val1 = Math.floor(val1 * factor) / factor
                val2 = Math.floor(val2 * factor) / factor
              }
            }

            // 比较值
            if (normalizeValue(val1) !== normalizeValue(val2)) {
              isDifferent = true
              differences.push({
                columnName: columnConfig.name,
                value1: val1,
                value2: val2,
              })

              // 更新列统计
              const colStat = columnStats.get(i)
              if (colStat) {
                colStat.different++

                // 只保存前3个示例
                if (colStat.examples.length < 3) {
                  colStat.examples.push({
                    excel1: val1,
                    excel2: val2,
                    rowNum1: rowIndex1,
                    rowNum2: excel2Record.rowIndex,
                    uniqueKey: generateRowId(row1, sortFieldIndices),
                  })
                }
              }
            }
          }
        }

        if (isDifferent) {
          await indexedDBUtil.saveCompareResult({
            type: 'different',
            excel1Data: row1,
            excel2Data: row2,
            rowNum1: rowIndex1,
            rowNum2: excel2Record.rowIndex,
            differences,
          })
        }
      }
    }
    console.log('compare finished')
    console.log(columnStats)
    // 更新列配置的比较结果
    columnConfigs.value.forEach((config, index) => {
      if (config.comparisonResult !== 'not-exist') {
        const colStat = columnStats.get(index)
        if (colStat && colStat.different > 0) {
          config.comparisonResult = 'different'
          config.examples = colStat.examples
        } else {
          config.comparisonResult = 'identical'
          config.examples = []
        }
      }
    })

    // 在对比完成后设置comparisonResult
    const differences = await indexedDBUtil.getAllCompareResults()
    const result = {
      totalRows: excel1Data.value.length - 1, // 减去表头行
      matchedRows: 0,
      differentRows: 0,
      onlyInFile1: 0,
      onlyInFile2: 0,
      differences: differences.map((diff) => ({
        row: diff.rowNum1 || diff.rowNum2 || 0,
        type: diff.type,
        content1: diff.excel1Data ? JSON.stringify(diff.excel1Data) : null,
        content2: diff.excel2Data ? JSON.stringify(diff.excel2Data) : null,
      })),
    }

    // 统计各类型的数量
    differences.forEach((diff) => {
      if (diff.type === 'different') {
        result.differentRows++
      } else if (diff.type === 'only-in-file1') {
        result.onlyInFile1++
      } else if (diff.type === 'only-in-file2') {
        result.onlyInFile2++
      }
    })

    result.matchedRows = result.totalRows - result.differentRows - result.onlyInFile1

    // 设置对比结果
    comparisonResult.value = result

    // ... 其余代码保持不变 ...
  } catch (error) {
    console.error('比较失败:', error)
    ElMessage.error(error instanceof Error ? error.message : '比较失败，请重试')
  } finally {
    isComparing.value = false
    showCompareAnimation.value = false
  }
}

// 标准化值以进行比较
const normalizeValue = (value: any): string => {
  if (value === null || value === undefined) {
    return ''
  }

  let strValue = String(value)

  if (ignoreCase.value) {
    strValue = strValue.toLowerCase()
  }

  if (ignoreSpaces.value) {
    strValue = strValue.trim().replace(/\s+/g, ' ')
  }

  return strValue
}

// 获取差异类型的文本描述
const getDiffTypeText = (type: string): string => {
  switch (type) {
    case 'different':
      return '内容不同'
    case 'only-in-file1':
      return '仅在文件1中'
    case 'only-in-file2':
      return '仅在文件2中'
    default:
      return type
  }
}

// 添加下载CSV结果的函数
const downloadResultsAsCsv = async () => {
  if (!comparisonResult.value) return

  // 显示下载动画
  downloadProgress.value = 10
  downloadStage.value = '准备导出CSV数据...'
  showDownloadAnimation.value = true

  try {
    const headers1 = excel1Data.value[0] || []

    // 获取排序字段的索引
    const sortFieldIndices: number[] = []
    for (const config of sortConfigs.value) {
      const index = headers1.findIndex((h: string) => h === config.field)
      if (index !== -1) {
        sortFieldIndices.push(index)
      }
    }

    // 获取需要对比的列
    const columnsToCompare = columnConfigs.value
      .filter((config) => config.shouldCompare)
      .map((config) => config.name)

    // 准备CSV文件内容
    let csvContent = '"行号","排序字段","差异类型","差异内容"\n'

    // CSV处理函数 - 处理字段中的特殊字符
    const escapeCSV = (field: string) => {
      const escaped = field.replace(/"/g, '""')
      return escaped.includes(',') || escaped.includes('\n') || escaped.includes('"')
        ? `"${escaped}"`
        : escaped
    }

    // 获取所有差异记录
    const differences = await indexedDBUtil.getAllCompareResults()
    const totalItems = differences.length

    // 分批处理差异数据
    const BATCH_SIZE = 1000
    const batchCount = Math.ceil(totalItems / BATCH_SIZE)

    for (let batch = 0; batch < batchCount; batch++) {
      // 更新进度
      const progressPercent = 20 + Math.floor((batch / batchCount) * 70)
      downloadProgress.value = progressPercent
      downloadStage.value = `处理数据 ${batch * BATCH_SIZE + 1}-${Math.min((batch + 1) * BATCH_SIZE, totalItems)} / ${totalItems}...`

      // 等待一小段时间，让UI有机会更新
      await new Promise((resolve) => setTimeout(resolve, 0))

      // 处理当前批次
      const startIndex = batch * BATCH_SIZE
      const endIndex = Math.min((batch + 1) * BATCH_SIZE, totalItems)
      const batchDifferences = differences.slice(startIndex, endIndex)

      for (const diff of batchDifferences) {
        // 获取排序字段值
        let sortFieldValues = '无排序字段'

        if (diff.type === 'only-in-file1' && diff.excel1Data) {
          try {
            const row = diff.excel1Data
            if (sortFieldIndices.length > 0) {
              sortFieldValues = sortFieldIndices
                .map((idx) => {
                  const fieldName = headers1[idx]
                  return `${fieldName}:${row[idx] || '空值'}`
                })
                .join('; ')
            }
          } catch (e) {
            console.error('解析失败:', e)
          }
        } else if (diff.type === 'only-in-file2' && diff.excel2Data) {
          sortFieldValues = '仅在Excel2中'
        } else if (diff.type === 'different' && diff.excel1Data) {
          try {
            const row = diff.excel1Data
            if (sortFieldIndices.length > 0) {
              sortFieldValues = sortFieldIndices
                .map((idx) => {
                  const fieldName = headers1[idx]
                  return `${fieldName}:${row[idx] || '空值'}`
                })
                .join('; ')
            }
          } catch (e) {
            console.error('解析失败:', e)
          }
        }

        // 提取差异内容
        let diffContent = '-'
        if (diff.type === 'different' && diff.differences) {
          // 使用新的differences字段
          diffContent = diff.differences
            .filter((d: { columnName: string }) => columnsToCompare.includes(d.columnName))
            .map(
              (d: { columnName: string; value1: any; value2: any }) =>
                `${d.columnName} Excel1:${d.value1 || '空值'} Excel2:${d.value2 || '空值'}`,
            )
            .join('; ')
        } else if (diff.type === 'only-in-file1') {
          diffContent = '仅在Excel1中存在'
        } else if (diff.type === 'only-in-file2') {
          diffContent = '仅在Excel2中存在'
        }

        // 添加到CSV内容
        csvContent += `${escapeCSV(String(diff.rowNum1 || diff.rowNum2 || '未知'))},${escapeCSV(sortFieldValues)},${escapeCSV(getDiffTypeText(diff.type))},${escapeCSV(diffContent)}\n`
      }
    }

    // 下载CSV文件
    downloadStage.value = '生成CSV文件...'
    downloadProgress.value = 95
    await new Promise((resolve) => setTimeout(resolve, 300))

    // 添加BOM头以确保Excel正确识别中文编码
    const BOM = '\uFEFF'
    const blob = new Blob([BOM + csvContent], { type: 'text/csv;charset=utf-8' })
    const url = URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = url
    link.download = 'excel_comparison_result.csv'
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    URL.revokeObjectURL(url)

    // 完成
    downloadProgress.value = 100
    downloadStage.value = '导出完成！'
    await new Promise((resolve) => setTimeout(resolve, 500))
    showDownloadAnimation.value = false

    ElMessage.success('对比结果已下载为CSV格式')
  } catch (error) {
    console.error('下载失败:', error)
    ElMessage.error('下载失败，请重试')
    showDownloadAnimation.value = false
  }
}

// 全选所有列
const selectAllColumns = () => {
  columnConfigs.value.forEach((config) => (config.shouldCompare = true))
  ElMessage.success('已全选所有字段')
}

// 全不选所有列
const deselectAllColumns = () => {
  columnConfigs.value.forEach((config) => (config.shouldCompare = false))
  ElMessage.success('已取消选择所有字段')
}

// 在组件卸载时清理数据
onUnmounted(async () => {
  try {
    // 清空所有数据
    await indexedDBUtil.clearAllData()
  } catch (error) {
    console.error('清理数据失败:', error)
  }
})
</script>

<style scoped>
/* 自定义Element Loading样式 */
/* :deep(.custom-loading-class) {
  background-color: rgba(17, 24, 39, 0.9) !important;
}

:deep(.custom-loading-class .el-loading-text) {
  color: white;
  font-size: 16px;
  margin-top: 15px;
}

:deep(.custom-loading-class .el-loading-spinner) {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin-top: 20px;
}

:deep(.custom-loading-class .el-loading-spinner i) {
  font-size: 40px;
  color: #4f46e5;
} */

.excel-compare-container {
  width: 100%;
  height: 100vh;
  overflow-y: auto;
  background-color: #f5f7f8;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}

.excel-compare {
  padding: 20px;
  max-width: 1200px;
  margin: 0 auto;
  font-family:
    -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}

.card {
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.06);
  padding: 24px;
  margin-bottom: 20px;
}

.card-header {
  border-bottom: 1px solid #edf2f7;
  padding-bottom: 20px;
  margin-bottom: 24px;
}

.card-header h2 {
  margin: 0;
  font-size: 20px;
  color: #2d3748;
  font-weight: 600;
}

.upload-section {
  margin-bottom: 24px;
}

.file-uploads {
  display: flex;
  gap: 24px;
  flex-wrap: wrap;
}

.file-upload-container {
  flex: 1;
  min-width: 300px;
}

.file-upload-container h3 {
  margin: 0 0 12px 0;
  font-size: 16px;
  color: #2d3748;
  font-weight: 500;
}

.file-upload {
  position: relative;
  display: block;
  padding: 24px;
  border: 2px dashed #e2e8f0;
  border-radius: 8px;
  background: #f8fafc;
  transition: all 0.3s ease;
  text-align: center;
  width: 100%;
}

.file-upload.dragover {
  border-color: #4f46e5;
  background: #eef2ff;
}

.file-input {
  position: absolute;
  width: 0;
  height: 0;
  opacity: 0;
}

.upload-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 24px;
  background: #4f46e5;
  color: white;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.3s ease;
  font-weight: 500;
  width: 80%;
  max-width: 300px;
  font-size: 14px;
}

.upload-button:hover {
  background: #4338ca;
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(79, 70, 229, 0.2);
}

.drag-tip {
  margin-top: 10px;
  color: #64748b;
  font-size: 14px;
}

.file-name {
  margin-top: 12px;
  color: #4f46e5;
  font-size: 14px;
  font-weight: 500;
}

.preview-section {
  margin-top: 24px;
}

.preview-section h3 {
  font-size: 16px;
  color: #2d3748;
  margin-bottom: 12px;
  font-weight: 500;
}

.table-wrapper {
  overflow-x: auto;
  border-radius: 8px;
  border: 1px solid #e2e8f0;
}

.preview-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  text-align: left;
}

.preview-table th,
.preview-table td {
  padding: 12px 16px;
  border-bottom: 1px solid #e2e8f0;
  font-size: 14px;
}

.preview-table th {
  background: #f8fafc;
  font-weight: 600;
  color: #475569;
  white-space: nowrap;
}

.preview-table tr:last-child td {
  border-bottom: none;
}

.columns-config-section {
  margin-top: 24px;
}

.columns-config-section h3 {
  font-size: 16px;
  color: #2d3748;
  margin-bottom: 12px;
  font-weight: 500;
}

.config-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  text-align: left;
}

.config-table th,
.config-table td {
  padding: 12px 16px;
  border-bottom: 1px solid #e2e8f0;
  font-size: 14px;
}

.config-table th {
  background: #f8fafc;
  font-weight: 600;
  color: #475569;
  white-space: nowrap;
}

.config-table tr:last-child td {
  border-bottom: none;
}

.config-table tr.different {
  background: #fff5f5;
}

.config-table tr.only-in-file1 {
  background: #f0fdf4;
}

.config-table tr.only-in-file2 {
  background: #eff6ff;
}

.config-item {
  display: flex;
  align-items: center;
  gap: 8px;
}

.config-label {
  white-space: nowrap;
  color: #475569;
  font-size: 14px;
  font-weight: 500;
}

.text-input {
  padding: 8px 12px;
  border: 1px solid #e2e8f0;
  border-radius: 6px;
  width: 160px;
  font-size: 14px;
  transition: all 0.3s ease;
}

.text-input:hover {
  border-color: #cbd5e1;
}

.text-input:focus {
  border-color: #4f46e5;
  outline: none;
  box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
}

.select-input {
  padding: 8px 12px;
  border: 1px solid #e2e8f0;
  border-radius: 6px;
  width: 160px;
  background: white;
  font-size: 14px;
  cursor: pointer;
  transition: all 0.3s ease;
}

.select-input:hover {
  border-color: #cbd5e1;
}

.select-input:focus {
  border-color: #4f46e5;
  outline: none;
  box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
}

.checkbox-wrapper {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  user-select: none;
}

.checkbox-wrapper input[type='checkbox'] {
  width: 16px;
  height: 16px;
  margin: 0;
  cursor: pointer;
}

.checkbox-wrapper span {
  font-size: 14px;
  color: #475569;
}

.digit-input {
  padding: 8px 12px;
  border: 1px solid #e2e8f0;
  border-radius: 6px;
  width: 160px;
  font-size: 14px;
  transition: all 0.3s ease;
}

.digit-input:hover {
  border-color: #cbd5e1;
}

.digit-input:focus {
  border-color: #4f46e5;
  outline: none;
  box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
}

.action-section {
  margin-bottom: 24px;
  text-align: center;
}

.compare-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 32px;
  background: #4f46e5;
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.3s ease;
  font-size: 16px;
  font-weight: 500;
  min-width: 200px;
}

.compare-btn:hover:not(:disabled) {
  background: #4338ca;
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(79, 70, 229, 0.2);
}

.compare-btn:disabled {
  background: #94a3b8;
  cursor: not-allowed;
}

.result-section {
  margin-top: 32px;
}

.result-section h3 {
  font-size: 18px;
  color: #2d3748;
  margin-bottom: 16px;
  font-weight: 600;
}

.result-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  background: #f8fafc;
  border-radius: 8px;
  padding: 16px;
  margin-bottom: 16px;
}

.summary-item {
  display: flex;
  align-items: center;
  gap: 8px;
}

.summary-item .label {
  color: #64748b;
  font-size: 14px;
}

.summary-item .value {
  color: #1e293b;
  font-size: 16px;
  font-weight: 600;
}

.result-actions {
  margin: 16px 0;
  display: flex;
  justify-content: flex-start;
}

.download-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 24px;
  background: #10b981;
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.3s ease;
  font-size: 14px;
  font-weight: 500;
  min-width: 180px;
}

.download-btn:hover {
  background: #059669;
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(16, 185, 129, 0.2);
}

.diff-preview {
  margin-top: 24px;
}

.diff-preview h4 {
  font-size: 16px;
  color: #2d3748;
  margin-bottom: 12px;
  font-weight: 500;
}

.diff-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  text-align: left;
}

.diff-table th,
.diff-table td {
  padding: 12px 16px;
  border-bottom: 1px solid #e2e8f0;
  font-size: 14px;
}

.diff-table th {
  background: #f8fafc;
  font-weight: 600;
  color: #475569;
  white-space: nowrap;
}

.diff-table tr:last-child td {
  border-bottom: none;
}

.diff-table tr.different {
  background: #fff5f5;
}

.diff-table tr.only-in-file1 {
  background: #f0fdf4;
}

.diff-table tr.only-in-file2 {
  background: #eff6ff;
}

.status-identical {
  color: #22c55e;
  font-weight: 600;
}

.status-different {
  color: #ef4444;
  font-weight: 600;
}

.status-not-exist {
  color: #f59e0b;
  font-weight: 600;
}

.examples-wrapper {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.example-item {
  background: #f8fafc;
  padding: 8px;
  border-radius: 4px;
  font-size: 12px;
  border-left: 3px solid #4f46e5;
}

.example-row {
  margin-bottom: 4px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.example-row-num {
  font-weight: 500;
  color: #4f46e5;
  font-size: 11px;
}

.row-label {
  font-size: 11px;
  color: #64748b;
}

.row-value {
  font-size: 11px;
  color: #4f46e5;
}

.row-number {
  font-weight: 600;
}

.example-content {
  font-size: 12px;
  margin-top: 2px;
}

.example-item .value {
  font-weight: 600;
  margin-right: 8px;
}

/* 加载动画样式 */
.loading-spinner {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 12px;
}

.spinner {
  width: 40px;
  height: 40px;
  border: 4px solid rgba(79, 70, 229, 0.1);
  border-left-color: #4f46e5;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

.loading-text {
  margin-top: 8px;
  color: #4f46e5;
  font-size: 14px;
  font-weight: 500;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

.config-section {
  background: #f8fafc;
  border-radius: 8px;
  padding: 16px;
  margin-bottom: 24px;
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

/* 排序相关样式 */
.sort-section {
  margin-top: 24px;
  background: #f8fafc;
  border-radius: 8px;
  padding: 16px;
  margin-bottom: 24px;
}

.sort-section h3 {
  font-size: 16px;
  color: #2d3748;
  margin-bottom: 16px;
  font-weight: 500;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.sort-info {
  font-size: 13px;
  color: #4f46e5;
  font-weight: normal;
  font-style: italic;
}

.sort-header {
  display: flex;
  margin-bottom: 8px;
  font-weight: 500;
  color: #4a5568;
}

.sort-header-left,
.sort-item-left {
  flex: 2;
  padding-right: 8px;
}

.sort-header-center,
.sort-item-center {
  flex: 1;
  padding: 0 8px;
}

.sort-header-right,
.sort-item-right {
  flex: 1;
  padding-left: 8px;
}

.header-text {
  display: inline-block;
  padding: 0 8px;
}

.sort-configs {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.sort-item {
  display: flex;
  align-items: center;
}

.sort-item-actions {
  display: flex;
  gap: 4px;
  margin-left: 8px;
}

.icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  background: white;
  border: 1px solid #e2e8f0;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.2s ease;
}

.icon-btn:hover:not(:disabled) {
  background: #f1f5f9;
  border-color: #cbd5e1;
}

.icon-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.icon {
  font-size: 16px;
  color: #4b5563;
}

.warning-text {
  color: #f59e0b;
  font-size: 14px;
  font-weight: 500;
  display: inline-block;
  background-color: #fff7ed;
  padding: 8px 12px;
  border-radius: 6px;
  border-left: 3px solid #f59e0b;
}

@media (max-width: 768px) {
  .file-uploads {
    flex-direction: column;
  }

  .config-section {
    flex-direction: column;
    align-items: flex-start;
  }

  .result-summary {
    flex-direction: column;
  }
}

/* 添加全屏加载动画样式 */
.fullscreen-loader {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(17, 24, 39, 0.9);
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
}

.compare-animation {
  width: 300px;
  background-color: rgba(0, 0, 0, 0.4);
  border-radius: 16px;
  padding: 32px;
  text-align: center;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
  backdrop-filter: blur(8px);
}

.compare-spinner {
  width: 60px;
  height: 60px;
  border: 5px solid rgba(79, 70, 229, 0.2);
  border-radius: 50%;
  border-top-color: #4f46e5;
  margin: 0 auto 20px;
  animation: spin 1s linear infinite;
}

.compare-text {
  color: white;
  font-size: 20px;
  margin-bottom: 8px;
  font-weight: 600;
}

.compare-stage {
  color: #a5b4fc;
  font-size: 16px;
  margin-bottom: 24px;
}

.progress-container {
  width: 100%;
  height: 8px;
  background-color: rgba(255, 255, 255, 0.1);
  border-radius: 4px;
  overflow: hidden;
  margin-bottom: 8px;
}

.progress-bar {
  height: 100%;
  background-color: #4f46e5;
  border-radius: 4px;
  transition: width 0.3s ease;
}

.progress-text {
  color: white;
  font-size: 14px;
  text-align: right;
}

/* 淡入淡出动画 */
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

.select-all-controls {
  display: flex;
  gap: 10px;
  margin-top: 8px;
  justify-content: center;
}

.mini-btn {
  padding: 4px 8px;
  background: #4f46e5;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 12px;
  transition: all 0.2s ease;
}

.mini-btn:hover {
  background: #4338ca;
}

.select-all {
  background: #4f46e5;
}

.deselect-all {
  background: #64748b;
}

.deselect-all:hover {
  background: #475569;
}

.th-content {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.th-label {
  margin-bottom: 8px;
}

.select-all-controls {
  display: flex;
  gap: 6px;
  justify-content: center;
}

.checkbox-cell {
  text-align: center;
}

.file-info {
  margin-top: 8px;
  color: #4f46e5;
  font-size: 14px;
  font-weight: 500;
  background: #eef2ff;
  padding: 4px 8px;
  border-radius: 4px;
  display: inline-block;
}

.example-unique-key {
  margin-top: 4px;
  font-size: 12px;
  color: #4f46e5;
  background: #eef2ff;
  padding: 4px 8px;
  border-radius: 4px;
  word-break: break-all;
}

.key-label {
  color: #6b7280;
  margin-right: 8px;
}

.key-value {
  font-family: monospace;
  font-weight: 500;
}
</style>
